"use strict";
const { models: FModels, redis: RedisClient } = require("../connect");
const { User } = FModels;
const bcrypt = require("bcryptjs");
const jsonwebtoken = require("jsonwebtoken");
const FError = require("../util/FError");
const { FUtil, FEnum } = require("../util");
const config = require("../config/config");

exports.generateAdmin = async userBody => {
  const { account, email } = userBody;
  const user = await User.findOne({ account });
  if (user) return false;
  return await new User({ account, email }).save();
};

exports.validateLogin = async userBody => {
  const { account, password } = userBody;
  const user = await User.findOne({ account });
  if (!user) throw FError.NotFoundUser("no user found", 403);
  const pass = bcrypt.compareSync(password, user.password);
  if (!pass) throw FError.VerifyFailure("wrong password", 403);
  return await formatToken(user);
};

async function formatToken(user) {
  user = FUtil.mongoToObject(user);
  const key = FEnum.RedisKey.tokenKey.format({ uid: user._id });
  await RedisClient.del(key);
  const expireTime = FEnum.MaxLimit.TokenExpireTime;
  const token = jsonwebtoken.sign(
    { data: user, exp: Math.floor(Date.now() / 1000) + expireTime },
    config.aesSecret
  );
  await RedisClient.multi()
    .set(key, token)
    .pexpire(key, jsonwebtoken.verify(token, config.aesSecret).exp - 20000) //提前20s过期
    .exec();
  return user;
}

exports.updatePassword = async userBody => {
  const { account, originPass, newPass } = userBody;
  const user = await User.findOne({ account });
  if (!user) throw FError.NotFoundUser(`not user found`, 404);
  const validate = await bcrypt.compareSync(originPass, user.password);
  if (!validate)
    throw FError.VerifyFailure(`wrong password or verification`, 403);
  return await User.updateOne(
    { account },
    { $set: { password: bcrypt.hashSync(newPass, 5) } }
  );
};
